﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;

using System.Linq;

using $prjsn$.Common;

using ProjectBase.Core;
using ProjectBase.Core.Service;
using ProjectBase.Core.Tools.Import;

namespace $safeprojectname$
{
    public class ImportProvider : IImportProvider, IMessagesHolder
    {
        public bool Execute<TEntity, TID>(byte[] dataSource, Action<IValueContainer> action = null)
            where TEntity : class, IPersistentObjectWithTypedId<TID>
        {
            if (dataSource.IsEmpty())
            {
                this.PublishWarning("No Excel file as data source was loaded");
                return false;
            }

            try
            {
                if (ExcelImporter.IsNull() || ImportModel.IsNull())
                {
                    this.PublishWarning("there is no Excel Importer (IExcelImporter or IImporterData) implementation");
                    return false;
                }

                ImportModel.DataSource = dataSource;
                var records = ExcelImporter.Execute(ImportModel);

                return ProcessResults<TEntity, TID>(records, action);
            }
            catch (Exception ex)
            {
                this.PublishFatal("Import from MS Excel was not successfull", ex);
            }
            return false;
        }

        protected virtual bool ProcessResults<TEntity, TID>(IEnumerable<IValueContainer> records, Action<IValueContainer> action)
            where TEntity : class, IPersistentObjectWithTypedId<TID>
        {
            if (records.IsNull())
            {
                this.PublishWarning("No records were found, cannot proceed to import");
                return false;
            }

            var processor = Factory.CreateInstance<IEntityFacade<TEntity, TID>>();

            foreach (var record in records)
            {
                if (action.Is())
                {
                    action(record); // callback to facade to decide ...
                    continue;
                }

                ProcessRecord(record, processor);
            }

            if (Messages.ContainsError())
            {
                this.PublishWarning(Str.Messages.ImportWasNotSuccessful1, records.Count());
                return false;
            }

            this.PublishInfo(Str.Messages.ImportWasSuccessful1, records.Count());
            return true;
        }

        protected virtual void ProcessRecord<TEntity, TID>(IValueContainer record, IEntityFacade<TEntity, TID> processor)
            where TEntity : class, IPersistentObjectWithTypedId<TID>
        {
            TEntity entity;

            if (record.ContainsPrefix(Str.Common.ID)
               && record.GetValue(Str.Common.ID).AttemptedValue.IsNotEmpty())
            {
                var id = (TID)record.GetValue(Str.Common.ID).ConvertTo(typeof(TID));
                entity = processor.GetById(id);
                if (entity.IsNull())
                {
                    this.PublishError(Str.Messages.RecordToUpdateHasUnknownID1, id);
                    return;
                }
                processor.BindEntity(entity, record);
                processor.Update(entity);
            }
            else
            {
                entity = processor.CreateNew();
                processor.BindEntity(entity, record);
                processor.Add(entity);
            }
        }

        #region properties
        public virtual Messages Messages { get; set; }
        public virtual IExcelImporter ExcelImporter { protected get; set; }
        public virtual IImporterData ImportModel { protected get; set; }
        #endregion properties
    }
}
